package common

import (
	"crypto/md5"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/astaxie/beego/orm"
	"math/rand"
	"os"
	"strconv"
	"strings"
	"time"
	"unicode/utf8"
)

//事件日志
func NewEventLog(eventLog map[string]interface{}, multiOrm ...orm.Ormer) (int64, error) {
	o := NewOrm(multiOrm, DBChessLog)
	eventLog["create_time"] = time.Now().Unix()
	values, sql := InsertSql(TableEventLog, eventLog)
	result, err := o.Raw(sql, values).Exec()
	if err != nil {
		return 0, err
	}
	return result.LastInsertId()
}

func Md5sum(plaintext string) (ciphertext string) {
	h := md5.New()
	h.Write([]byte(plaintext))
	ciphertext = fmt.Sprintf("%x", h.Sum(nil))
	return
}

func NewOrm(multiOrm []orm.Ormer, db ...string) (o orm.Ormer) {
	if len(multiOrm) == 0 {
		o = orm.NewOrm()
		if len(db) == 1 {
			o.Using(db[0])
		}
	} else if len(multiOrm) == 1 {
		o = multiOrm[0]
	} else {
		panic("只能传一个Ormer")
	}
	return
}
func NewDBOrm(dbName string) (o orm.Ormer) {
	o = orm.NewOrm()
	o.Using(dbName)
	return
}

func Join(a []int64, sep string) string {
	return strings.Trim(strings.Join(strings.Split(fmt.Sprint(a), " "), sep), "[]")
}

//结构体转map
func StructToMap(v interface{}) (map[string]interface{}, error) {
	str, err := json.Marshal(v)
	if err != nil {
		return nil, err
	}
	mapInfo := make(map[string]interface{})
	err = json.Unmarshal([]byte(str), &mapInfo)
	if err != nil {
		return nil, err
	}
	return mapInfo, nil
}

//生成8位授权码,去掉不吉利的数字4与7, 一共有16777216组合
func GenerateAuthCode() string {
	str := "01235689"
	var result string
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < 8; i++ {
		result = result + string(str[r.Intn(len(str))])
	}
	return result
}

func IsPathExist(path string) bool {
	_, err := os.Stat(path)
	if err != nil || os.IsNotExist(err) {
		return false
	}
	return true
}

//返回true表示有错误,没有数据不算是错误
func CheckError(err error) bool {
	if err != nil && err != orm.ErrNoRows {
		return true
	}
	return false
}

//返回true就表示不存在
func CheckNoExist(err error) bool {
	if err == orm.ErrNoRows {
		return true
	}
	return false
}

const (
	ErrorHappen = 1 //有错误
	NoError     = 2 //没错误
	NoExist     = 3 //不存在
	InvalidConn = 4 //invalid connection,bad connection

	NoExistOrError = 5 //不存在或有错误
)

func CheckErrorStatus(err error) int64 {
	switch err {
	case ErrBadConnNoWrite:
		return InvalidConn
	case ErrInvalidConn:
		return InvalidConn
	case orm.ErrNoRows:
		return NoExist
	case nil:
		return NoError
	default:
		return ErrorHappen
	}

}

//隐藏手机号中间四位,如13412345678 ---> 134****5678
func HidePhoneNumber(phone string) string {
	if len(phone) != 11 {
		return phone
	}
	return phone[:3] + "****" + phone[7:]
}

//生成游戏id
func GenGameId(gameType, playType interface{}) int64 {
	gameIdStr := fmt.Sprintf("%003v%003v", gameType, playType)
	gameId, _ := strconv.Atoi(gameIdStr)
	return int64(gameId)
}

//反解游戏id,返回game_type,play_type
func AnalysisGameId(gameId int64) (int, int) {
	game := fmt.Sprintf("%v", gameId)
	length := len(game)
	if length < 4 {
		return 0, 0
	}
	gameType, _ := strconv.Atoi(game[:length-3])
	playType, _ := strconv.Atoi(game[length-3:])
	return gameType, playType
}

func MathAbs(i int64) int64 {
	if i < 0 {
		return -i
	}
	if i == 0 {
		return 0
	}
	return i
}

//因配置改动要清理redis缓存
func ClearRedisCache(key string) error {
	//先匹配到所有符合此key的
	keys, err := Redis.Keys(key + "*")
	if err != nil {
		return err
	}
	for _, v := range keys {
		_, err = Redis.Del(v)
		if err != nil {
			return err
		}
	}
	return err
}

//返回玩家离线了多久
func OfflineTime(offlineTime int64) string {
	sub := time.Now().Unix() - offlineTime
	if sub < 60 {
		return "刚刚"
	} else if sub < 3600 {
		return fmt.Sprintf("%v分钟前", sub/60)
	} else if sub < 86400 { //hour
		return fmt.Sprintf("%v小时前", sub/3600)
	} else if sub < 604800 { //day
		return fmt.Sprintf("%v天前", sub/(86400))
	} else if sub < 2592000 { //week
		return fmt.Sprintf("%v周前", sub/(604800))
	} else if sub < 31104000 { //month
		return fmt.Sprintf("%v月前", sub/(2592000))
	}
	//specify time
	return time.Unix(offlineTime, 0).Format("2006-01-02 15:04")
}

/*
 *desc:用于访问次数限制
 *@key:需要以什么来做标识做访问次数限制的标志
 *@frequency: 次数
 *@expireTime:多少秒超时
 */
func AccessLimit(key string, frequency int64, expireTime int64) bool {
	ok := MemCache.IsExist(key)
	if !ok { //doesn't exist, set a key and expire time
		MemCache.Put(key, 1, time.Duration(expireTime)*time.Second)
		return true
	}

	f := MemCache.GetInt64(key)
	if f < frequency {
		MemCache.Incr(key)
		return true
	}
	LogClient.Debug(fmt.Sprintf("触及访问限速,key:%v,frequency:%v,expireTime:%v", key, frequency, expireTime))
	return false
}

//添加定时器事件
func AddTimerEvent(f func() error, t int64) error {
	now := int64(time.Now().Unix())
	if t <= now {
		return errors.New("时间戳小于当前时间")
	}
	go func() {
		timer := time.NewTimer(time.Duration(t-now) * time.Second)
		<-timer.C
		f()
	}()
	return nil
}

//获取排序是升序还是降序
func GetOrderSort(defaultOrder string, order int64) string {
	if order == 1 {
		return "ASC"
	} else if order == 2 {
		return "DESC"
	}
	return defaultOrder
}

func FilterEmoji(content string) string {
	newContent := ""
	for _, value := range content {
		_, size := utf8.DecodeRuneInString(string(value))
		if size <= 3 {
			newContent += string(value)
		} else {
			newContent += "*"
		}
	}
	return newContent
}

//判断是否为纯数字
func IsNumber(number string) bool {
	for _, v := range number {
		if '9' < v || v < '0' {
			return false
		}
	}
	return true
}

//获取爱贝支付方式
func IPayPayType(payType int64) int64 {
	switch payType {
	case WeChatPay:
		return 403
	case AliPay:
		return 401
	}
	return 0
}

//检查表是否存在,不存在返回false,存在返回true
func CheckTableIsExist(tableName string) bool {
	sqlCheck := fmt.Sprintf(`
		SELECT
			TABLE_NAME
		FROM
			%v
		WHERE
			TABLE_NAME = '%v'
	`, TableTables, tableName)
	o := NewDBOrm(DBInformationSchema)
	var tn string
	err := o.Raw(sqlCheck).QueryRow(&tn)
	if CheckNoExist(err) {
		return false
	}
	return true
}
